﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Core;

namespace FindItNow
{
	class SearchResult
	{
		public string Path;
		public int Line;
		public string Text;
		public int LineScore;
		public int AreaScore;
	};

	class MatchMask
	{
		public int Line;
		public int DirectMatches;
		public int IndirectMatches;
	};

	static class FindHelpers
	{
		public static void BuildSearchResults(List<SearchResult> results, List<string> paths, List<Regex> regexes)
		{
			foreach (string path in paths)
			{
				var fileResults = new List<SearchResult>(1000);

				BuildFileSearchResults(fileResults, path, regexes);

				results.AddRange(fileResults);
			}
		}

		private static void BuildFileSearchResults(List<SearchResult> results, string path, List<Regex> regexes)
		{
			int line = 1;
			string contents = "";

			try
			{
				using (var reader = new StreamReader(path))
					contents = reader.ReadToEnd();
			}
			catch (IOException)
			{
				return;
			}

			var masks = new List<MatchMask>(results.Capacity);

			using (var reader = new StringReader(contents))
			{
				string current;

				while ((current = reader.ReadLine()) != null)
				{
					int lineMatches = 0;
					int lineScore = 0;

					for (int i = 0; i < regexes.Count; ++i)
					{
						if (!regexes[i].IsMatch(current))
							continue;

						lineMatches |= 1 << i;
						lineScore++;
					}

					if (lineMatches > 0)
					{
						results.Add(new SearchResult { Path = path, Line = line, Text = current, LineScore = lineScore });
						masks.Add(new MatchMask { Line = line, DirectMatches = lineMatches, IndirectMatches = lineMatches});
					}

					++line;
				}
			}

			PropagateDirectMatches(masks, 3);

			for (int i = 0; i < results.Count; ++i)
			{
				for (int j = 0; j < regexes.Count; ++j)
				{
					if ((masks[i].IndirectMatches & (1 << j)) != 0)
						results[i].AreaScore++;
				}
			}
		}

		private static void PropagateDirectMatches(List<MatchMask> masks, int numLinesToPropagate)
		{
			for (int i = 0; i < masks.Count; ++i)
			{
				for (int j = Math.Max(0, i - numLinesToPropagate); j < i; ++j)
				{
					if ((masks[i].Line - masks[j].Line) > numLinesToPropagate)
						continue;

					masks[j].IndirectMatches |= masks[i].DirectMatches;
					masks[i].IndirectMatches |= masks[j].DirectMatches;
				}
			}
		}
	}
}
